#include"include.h"

list_t *createList() {
  list_t *new;
  new = malloc(sizeof(list_t));
  new->front = NULL;
  new->back = NULL;
  new->current = NULL;
  new->size = 0;
  sem_init(&(new->lock), 0, 1);
  return new;
}

void addObject(list_t *list, void *data) {
   if(data == NULL)
      return;
  node_t *new;

  new = malloc(sizeof(node_t));
  new->data = data;
  new->next = NULL;

  if (list->back != NULL) 
     list->back->next = new;
  else 
     list->front = new;

  list->back = new;
  list->size++;
}

void *listPopBack(list_t *list)
{
   void *ret = NULL;
   if(list->back != NULL)
   {
      ret = list->back->data;
      ret = removeObject(list, ret);
   }
   return ret;
}

unsigned int listGetSize(list_t *l)
{
   return l->size;
}

int listIsEmpty(list_t *list)
{
   return (list->size == 0);
}

void *removeObject(list_t *list, void *obj)
{
   if(obj == NULL)
      return NULL;
   /*printf("Size is %d. Data is %p", list->size, obj);
   listPrintPointers(list);
   if(list->size < 0)
      sleep(1);*/
      

   node_t *prev,*cur;
   cur = list->front;
   while(cur != NULL)
   {
      if(cur->data == obj)
      {
         list->size--;
         if(cur == list->front)
         {
            list->front = cur->next;
            free(cur);
            return obj;
         }
         else
         {
            prev->next = cur->next;
            free(cur);
            return obj;
         }
      }
      else
      {
         prev = cur;
         cur = cur->next;
      }
   }
   return NULL;
}

void *getObject(list_t *list) {
  node_t *nodePtr = list->current;
  if (nodePtr == NULL) {
    return NULL;
  }
  list->current = list->current->next;
  return (nodePtr->data);
}

void resetList(list_t *list) {
  list->current = list->front;
}

int endList(list_t *list) {
  return (list->current == NULL);
}

void sortList(list_t *l, int (*compare)(const void *, const void *))
{
  node_t *tmpPtr = l->front;
  if(tmpPtr == NULL) // Empty list
    return;
  node_t *tmpNxt = tmpPtr->next;
  void *tmp;

  while(tmpNxt != NULL)
  {
    while(tmpNxt != tmpPtr)
    {
      if(compare(tmpNxt->data, tmpPtr->data) < 0)
      {
        tmp = tmpPtr->data;
        tmpPtr->data = tmpNxt->data;
        tmpNxt->data = tmp;
      }
      tmpPtr = tmpPtr->next;
    }
    tmpPtr = l->front;
    tmpNxt = tmpNxt->next;
  }
}

void clearList(list_t *list)
{
   list->size = 0;
   node_t *clptr = list->front;
   if(clptr == NULL)
      return;
   node_t *clnxt = clptr;

   while(clnxt != NULL)
   {
      clnxt = clptr->next;
      free(clptr);
      clptr = clnxt;
   }
   list->front = NULL;
   list->back = NULL;
   list->current = NULL;
   list->size = 0;
}

void clearListAndFreeElements(list_t *list)
{
   node_t *clptr = list->front;
   if(clptr == NULL)
      return;
   node_t *clnxt = clptr;

   while(clnxt != NULL)
   {
      clnxt = clptr->next;
      free(clptr->data);
      free(clptr);
      clptr = clnxt;
   }
   list->front = NULL;
   list->back = NULL;
   list->current = NULL;
   list->size = 0;
   free(list);
}

void clearListAndFreeElementsNP(list_t *list) // Doesn't free the list itself
{
   node_t *clptr = list->front;
   if(clptr == NULL)
      return;
   node_t *clnxt = clptr;

   while(clnxt != NULL)
   {
      clnxt = clptr->next;
      free(clptr->data);
      free(clptr);
      clptr = clnxt;
   }
   list->front = NULL;
   list->back = NULL;
   list->current = NULL;
   list->size = 0;
}

void listPrintPointers(list_t *l)
{
   node_t *ptr = l->front;
   printf("LIST: \n");
   while(ptr != NULL)
   {
      printf("   %p\n", ptr->data);
      ptr = ptr->next;
   }
   printf("\n");
}

void listLock(list_t *list)
{
   sem_wait(&(list->lock));
}

void listRelease(list_t *list)
{
   sem_post(&(list->lock));
}

int listIsLocked(list_t *list)
{
   int val;
   sem_getvalue((&list->lock), &val);
   return !val;
}
